package cas;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;

public class CAS {
    private static final Logger logger = LoggerFactory.getLogger(CAS.class);
    //初始值为0
    private static AtomicInteger balance = new AtomicInteger(0);
    // Lock
    private static Integer share = 0;

    private static ForkJoinPool pool =  new ForkJoinPool(4);

    public static void main(String[] args) throws InterruptedException {
//        int count = 2_000_0000;
        int count = 2_000_0000;

        long l = System.currentTimeMillis();
        for (int i = 0; i < count; i++) {
//            CompletableFuture.runAsync(() -> syncTransfer());
//            CompletableFuture.runAsync(() -> casLockTransfer(),pool);
            CompletableFuture.runAsync(() -> casTransfer(),pool);
            // CompletableFuture.runAsync(() -> transfer2());
        }

        Thread.sleep(1000);
        logger.info("我开始抢了！");
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        while (true) {
            if(share == count || balance.get()==count){
                break;
            }
//            logger.info("lock:{}!",share);
            // 如果不sleep就无法得到正确结果
//            Thread.sleep(1);
        }
        long l1 = System.currentTimeMillis();
        System.out.println(l1 - l);
        logger.info("每毫秒完成交易数:{}",count/(l1 - l));
    }

    public synchronized static void syncTransfer() {
        logger.debug("fetch lock: {}!",share);
        // 在这里安全的访问共享资源
        share = share + 1;
    }

    // CAS
    public static void casTransfer() {
        for (; ; ) {
            int old = balance.get();
            int _new = old + 1;
            if (balance.compareAndSet(old, _new)) {
                // 这逼玩应儿只能用来加个数。。。
                break;
            }
            logger.debug("Lock UNFETCHED!!",Thread.currentThread().getId());
        }
    }

    static Lock lock = new IConcurrentLock();
//    static Lock lock = new ReentrantLock();

    public static void casLockTransfer() {
            lock.lock();
            try {
                share = share + 1;
            }
            finally {
                lock.unlock();
            }
    }

    //FFA
    public static void ffaTransfer() {
        balance.addAndGet(1);
    }

}